查看原文
其他

Android 10.0系统启动之Zygote进程(二)-「Android取经之路」

IngresGe IngresGe 2021-11-05

前几节已经讲完了Android10.0的Init启动过程以及Zygote进程的架构。

Android取经之路——启动篇

Android系统架构-[Android取经之路]

Android是怎么启动的-[Android取经之路]

Android系统启动之init进程(一)-「Android取经之路」

Android系统启动之init进程(二)-「Android取经之路」

Android 10.0系统启动之init进程(三)-「Android取经之路」

Android 10.0系统启动之init进程(四)-「Android取经之路」

Android 10.0系统启动之Zygote进程(一)-「Android取经之路」

这一节开始分析Zygote在Nativate-C空间的启动源码。

4. Zygote进程启动源码分析

我们主要是分析Android Q(10.0) 的Zygote启动的源码。

4.1 Nativate-C世界的Zygote启动要代码调用流程:

4.1.1 [app_main.cpp] main()

Zygote本身是一个Native的应用程序,刚开始的进程名称为“app_process”,运行过程中,通过调用setArgv0将名字改为zygote 或者 zygote64(根据操作系统而来),最后通过runtime的start()方法来真正的加载虚拟机并进入JAVA世界。

int main(int argc, char* const argv[]){
//zygote传入的参数argv为“-Xzygote /system/bin --zygote --start-system-server --socket-name=zygote”
//zygote_secondary传入的参数argv为“-Xzygote /system/bin --zygote --socket-name=zygote_secondary”
...
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
//对于64位系统nice_name为zygote64; 32位系统为zygote
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
//是否需要启动system server
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
//启动进入独立的程序模式
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
//niceName 为当前进程别名,区别abi型号
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}
..
if (!className.isEmpty()) { //className不为空,说明是application启动模式
...
} else {
//进入zygote模式,新建Dalvik的缓存目录:/data/dalvik-cache
maybeCreateDalvikCache();
if (startSystemServer) { //加入start-system-server参数
args.add(String8("start-system-server"));
}
String8 abiFlag("--abi-list=");
abiFlag.append(prop);d(abiFlag); //加入--abi-list=参数 // In zygote mode, pass all remaining arguments to the zygote // main() method. for (; i < argc; ++i) { //将剩下的参数加入args args.add(String8(argv[i])); } }
...
if (!niceName.isEmpty()) {//设置一个“好听的昵称” zygote\zygote64,之前的名称是app_process runtime.setArgv0(niceName.string(), true /* setProcName */); }
if (zygote) { //如果是zygote启动模式,则加载ZygoteInit runtime.start("com.android.internal.os.ZygoteInit", args, zygote); } else if (className) { //如果是application启动模式,则加载RuntimeInit runtime.start("com.android.internal.os.RuntimeInit", args, zygote); } else { //没有指定类名或zygote,参数错误 fprintf(stderr, "Error: no class name or --zygote supplied.\n"); app_usage(); LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); }}

4.1.2 [AndroidRuntime.cpp] start()

start()函数主要做了三件事情,一调用startVm开启虚拟机,二调用startReg注册JNI方法,三就是使用JNI把Zygote进程启动起来。

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote){
ALOGD(">>>>>> START %s uid %d <<<<<<\n", className != NULL ? className : "(unknown)", getuid()); ... JniInvocation jni_invocation; jni_invocation.Init(NULL); JNIEnv* env; // 虚拟机创建,主要是关于虚拟机参数的设置 if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) { return; }
onVmCreated(env); //空函数,没有任何实现 // 注册JNI方法 if (startReg(env) < 0) { ALOGE("Unable to register all android natives\n"); return; }
jclass stringClass; jobjectArray strArray; jstring classNameStr; //等价 strArray= new String[options.size() + 1]; stringClass = env->FindClass("java/lang/String"); assert(stringClass != NULL); //等价 strArray[0] = "com.android.internal.os.ZygoteInit" strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL); assert(strArray != NULL); classNameStr = env->NewStringUTF(className); assert(classNameStr != NULL); env->SetObjectArrayElement(strArray, 0, classNameStr); //strArray[1] = "start-system-server"; //strArray[2] = "--abi-list=xxx"; //其中xxx为系统响应的cpu架构类型,比如arm64-v8a. for (size_t i = 0; i < options.size(); ++i) { jstring optionsStr = env->NewStringUTF(options.itemAt(i).string()); assert(optionsStr != NULL); env->SetObjectArrayElement(strArray, i + 1, optionsStr); } //将"com.android.internal.os.ZygoteInit"转换为"com/android/internal/os/ZygoteInit" char* slashClassName = toSlashClassName(className != NULL ? className : ""); jclass startClass = env->FindClass(slashClassName); //找到Zygoteinit类 if (startClass == NULL) { ALOGE("JavaVM unable to locate class '%s'\n", slashClassName); } else { //找到这个类后就继续找成员函数main方法的Mehtod ID jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); if (startMeth == NULL) { ALOGE("JavaVM unable to find main() in '%s'\n", className); } else { // 通过反射调用ZygoteInit.main()方法 env->CallStaticVoidMethod(startClass, startMeth, strArray); } } //释放相应对象的内存空间 free(slashClassName); ALOGD("Shutting down VM\n"); if (mJavaVM->DetachCurrentThread() != JNI_OK) ALOGW("Warning: unable to detach main thread\n"); if (mJavaVM->DestroyJavaVM() != 0) ALOGW("Warning: VM did not shut down cleanly\n");}

相关log:

01-10 11:20:31.369 722 722 D AndroidRuntime: >>>>>> START com.android.internal.os.ZygoteInit uid 0 <<<<<<
01-10 11:20:31.429 722 722 I AndroidRuntime: Using default boot image
01-10 11:20:31.429 722 722 I AndroidRuntime: Leaving lock profiling enabled

4.1.3 [JniInvocation.cpp] Init()

Init函数主要作用是初始化JNI,具体工作是首先通过dlopen加载libart.so获得其句柄,然后调用dlsym从libart.so中找到

JNI_GetDefaultJavaVMInitArgs、JNI_CreateJavaVM、JNI_GetCreatedJavaVMs三个函数地址,赋值给对应成员属性,这三个函数会在后续虚拟机创建中调用.

bool JniInvocation::Init(const char* library) { char buffer[PROP_VALUE_MAX];
const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE;
/*
* 1.dlopen功能是以指定模式打开指定的动态链接库文件,并返回一个句柄
* 2.RTLD_NOW表示需要在dlopen返回前,解析出所有未定义符号,如果解析不出来,在dlopen会返回NULL
* 3.RTLD_NODELETE表示在dlclose()期间不卸载库,并且在以后使用dlopen()重新加载库时不初始化库中的静态变量
*/
handle_ = dlopen(library, kDlopenFlags); // 获取libart.so的句柄
if (handle_ == NULL) { //获取失败打印错误日志并尝试再次打开libart.so
if (strcmp(library, kLibraryFallback) == 0) {
// Nothing else to try.
ALOGE("Failed to dlopen %s: %s", library, dlerror());
return false;
}
library = kLibraryFallback;
handle_ = dlopen(library, kDlopenFlags);
if (handle_ == NULL) {
ALOGE("Failed to dlopen %s: %s", library, dlerror());
return false;
}
}
/*
* 1.FindSymbol函数内部实际调用的是dlsym
* 2.dlsym作用是根据 动态链接库 操作句柄(handle)与符号(symbol),返回符号对应的地址
* 3.这里实际就是从libart.so中将JNI_GetDefaultJavaVMInitArgs等对应的地址存入&JNI_GetDefaultJavaVMInitArgs_中
*/
if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
"JNI_GetDefaultJavaVMInitArgs")) {
return false;
} indSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_), "JNI_CreateJavaVM")) { return false; } if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_), "JNI_GetCreatedJavaVMs")) { return false; } return true;}

4.1.4 [AndroidRuntime.cpp] startVm()

该函数主要作用就是配置虚拟机的相关参数,再调用之前 JniInvocation初始化得到的 JNI_CreateJavaVM_来启动虚拟机。

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool primary_zygote){
JavaVMInitArgs initArgs; ... // JNI检测功能,用于native层调用jni函数时进行常规检测,比较弱字符串格式是否符合要求,资源是否正确释放。 //该功能一般用于早期系统调试或手机Eng版,对于User版往往不会开启,引用该功能比较消耗系统CPU资源,降低系统性能。
bool checkJni = false; property_get("dalvik.vm.checkjni", propBuf, ""); if (strcmp(propBuf, "true") == 0) { checkJni = true; } else if (strcmp(propBuf, "false") != 0) {
/* property is neither true nor false; fall back on kernel parameter */ property_get("ro.kernel.android.checkjni", propBuf, ""); if (propBuf[0] == '1') { checkJni = true; } } ALOGV("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
if (checkJni) { /* extended JNI checking */ addOption("-Xcheck:jni"); } addOption("exit", (void*) runtime_exit); //将参数放入mOptions数组中 //对于不同的软硬件环境,这些参数往往需要调整、优化,从而使系统达到最佳性能 parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m"); parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m"); parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit="); parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree="); parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree="); ...
//检索生成指纹并将其提供给运行时这样,anr转储将包含指纹并可以解析。 std::string fingerprint = GetProperty("ro.build.fingerprint", ""); if (!fingerprint.empty()) { fingerprintBuf = "-Xfingerprint:" + fingerprint; addOption(fingerprintBuf.c_str()); }
initArgs.version = JNI_VERSION_1_4; initArgs.options = mOptions.editArray(); //将mOptions赋值给initArgs initArgs.nOptions = mOptions.size(); initArgs.ignoreUnrecognized = JNI_FALSE; //调用之前JniInvocation初始化的JNI_CreateJavaVM_, 参考[4.1.3] if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) { ALOGE("JNI_CreateJavaVM failed\n"); return -1; } return 0;
}

4.1.5 [AndroidRuntime.cpp] startReg()

startReg首先是设置了Android创建线程的处理函数,然后创建了一个200容量的局部引用作用域,用于确保不会出现OutOfMemoryException,最后就是调用register_jni_procs进行JNI方法的注册

int AndroidRuntime::startReg(JNIEnv* env){ ATRACE_NAME("RegisterAndroidNatives"); //设置Android创建线程的函数javaCreateThreadEtc,这个函数内部是通过Linux的clone来创建线程的 androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc); ALOGV("--- registering native functions ---\n"); //创建一个200容量的局部引用作用域,这个局部引用其实就是局部变量 env->PushLocalFrame(200); //注册JNI方法 if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) { env->PopLocalFrame(NULL); return -1; }
env->PopLocalFrame(NULL); //释放局部引用作用域 return 0;}

4.1.6 [Thread.cpp] androidSetCreateThreadFunc()

虚拟机启动后startReg()过程,会设置线程创建函数指针gCreateThreadFn指向javaCreateThreadEtc.

void androidSetCreateThreadFunc(android_create_thread_fn func) { gCreateThreadFn = func;}

4.1.7 [AndroidRuntime.cpp] register_jni_procs()

它的处理是交给RegJNIRec的mProc,RegJNIRec是个很简单的结构体,mProc是个函数指针

static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env){ for (size_t i = 0; i < count; i++) { if (array[i].mProc(env) < 0) {/ /调用gRegJNI的mProc,参考[4.1.8] return -1; } } return 0;}

4.1.8 [AndroidRuntime.cpp] gRegJNI()

gRegJNI 中是一堆函数指针,因此循环调用 gRegJNI 的mProc,即等价于调用其所对应的函数指针。

例如调用:register_com_android_internal_os_RuntimeInit

这是一个JNI函数动态注册的标准方法。

static const RegJNIRec gRegJNI[] = { REG_JNI(register_com_android_internal_os_RuntimeInit), REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit), REG_JNI(register_android_os_SystemClock), REG_JNI(register_android_util_EventLog), REG_JNI(register_android_util_Log), ...}
#define REG_JNI(name) { name, #name } struct RegJNIRec { int (*mProc)(JNIEnv*); };
int register_com_android_internal_os_RuntimeInit(JNIEnv* env){ const JNINativeMethod methods[] = { { "nativeFinishInit", "()V", (void*) com_android_internal_os_RuntimeInit_nativeFinishInit }, { "nativeSetExitWithoutCleanup", "(Z)V", (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup }, };
//跟Java侧的com/android/internal/os/RuntimeInit.java 的函数nativeFinishInit() 进行一一对应 return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit", methods, NELEM(methods));}

下一节进入JAVA世界,分析Zygote JAVA世界的启动流程

: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存